﻿
using BoilenEditor.Primitives;
using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows;


namespace BoilenEditor.Properties {

    // http://bloggingabout.net/blogs/erwyn/archive/2007/02/01/remembering-window-positions-in-wpf.aspx
    [TypeConverter( typeof( WindowSettings.WindowSettingsConverter ) )]
    public sealed partial class WindowSettings {

        public override string ToString( ) {
            return "{0} {1}".With( this.WindowState, this.WindowBounds );
        }

        public void Apply( Window window ) {
            Rect bounds = this.WindowBounds;
            if( !bounds.IsEmpty ) {
                window.Left = bounds.Left;
                window.Top = bounds.Top;
                window.Width = bounds.Width;
                window.Height = bounds.Height;
            }

            window.WindowState = this.WindowState;
        }

        public static WindowSettings Parse( string source ) {
            string[] parts = source.Split( new[] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries );
            WindowState state =
                parts.Length > 0
                    ? (WindowState)Enum.Parse( typeof( WindowState ), parts[0] )
                    : WindowState.Normal;
            Rect bounds =
                parts.Length > 1
                    ? Rect.Parse( parts[1] )
                    : Rect.Empty;
            return new WindowSettings( state, bounds );
        }


        private static void SettingNameChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) {
            Window window = (Window)d;
            string settingName = (string)e.NewValue;
            Monitor.Window( window, settingName );
        }


        private sealed class Monitor {
            private readonly Window window_;
            private readonly string settingName_;

            private Monitor( Window window, string settingName ) {
                this.window_ = window;
                this.settingName_ = settingName;
            }

            private WindowSettings WindowSettings {
                get { return (WindowSettings)Settings.Default[this.settingName_]; }
                set { Settings.Default[this.settingName_] = value; }
            }

            public override string ToString( ) {
                return "Monitoring {0} ({1})".With( this.settingName_, this.WindowSettings );
            }

            public static void Window( Window window, string settingName ) {
                Monitor monitor = new Monitor( window, settingName );
                window.Initialized += monitor.WindowInitialized;
                window.Closing += monitor.WindowClosing;
                window.Closed += monitor.WindowClosed;
            }

            private void WindowInitialized( object sender, EventArgs e ) {
                WindowSettings ws = this.WindowSettings;
                ws.Apply( this.window_ );
            }

            private void WindowClosing( object sender, EventArgs e ) {
                WindowState state = this.window_.WindowState;
                Rect bounds = this.window_.RestoreBounds;
                this.WindowSettings = new WindowSettings( state, bounds );
            }

            private void WindowClosed( object sender, EventArgs e ) {
                Settings.Default.Save( );
            }
        }

        private sealed class WindowSettingsConverter : TypeConverter {
            public override bool CanConvertTo( ITypeDescriptorContext context, Type destinationType ) {
                return destinationType == typeof( string );
            }

            public override bool CanConvertFrom( ITypeDescriptorContext context, Type sourceType ) {
                return sourceType == typeof( string );
            }

            public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType ) {
                WindowSettings settings = (WindowSettings)value;
                string result = settings.ToString( );
                return result;
            }

            public override object ConvertFrom( ITypeDescriptorContext context, CultureInfo culture, object value ) {
                string source = (string)value;
                WindowSettings result = WindowSettings.Parse( source );
                return result;
            }
        }

    }

}
